/**
 * @desc index
 * @author DragonTeam <https://www.bpmport.com>
 * @since 2024/10/31 16:12
 */
import type { BaseNode, BaseNodeBO, EventNode, ExpressionNode, GatewayNode, SubprocessNode } from '@/types'
import { clearNodeMap, createNode, setNodeInMap } from '@/utils/element-utils'

interface NodeJson {
  id: string
  type: string
  name: string
  businessData: BaseNodeBO

  nextNode?: NodeJson
  childNode?: NodeJson

  $parentRef?: BaseNode['id']

  // 特殊节点属性部分
  expression?: string
  expressionRefs?: NodeJson[]
  $defaultRef?: BaseNode['id']
}

// 转为可用 json
export function transformToJson(node: BaseNode): NodeJson | undefined {
  if (!node)
    return undefined

  const result: NodeJson = transformNodeToJson(node)

  let parent: NodeJson = result
  let cur: BaseNode | undefined = node.$next
  while (cur) {
    const nextNode = transformNodeToJson(cur)

    // 特殊处理子流程
    if (cur.type === 'subprocess') {
      nextNode.childNode = transformToJson((cur as SubprocessNode).$start as BaseNode)
    }

    parent.nextNode = nextNode

    cur = cur.$next
    parent = nextNode
  }

  return result
}
export function transformNodeToJson(node: BaseNode) {
  const {
    id,
    type,
    name,
    businessData,
  } = node
  const expression = (node as ExpressionNode).expression
  const expressions = (node as GatewayNode).$expressions
  const $default = (node as GatewayNode).$default

  const expressionRefs = expressions?.map(e => transformToJson(e)!)
  const $defaultRef = $default?.id

  const result: NodeJson = {
    id,
    type,
    name,
    businessData,
  }

  if (expressionRefs) {
    result.expressionRefs = expressionRefs
  }
  if (expression) {
    result.expression = expression
  }

  if ($defaultRef) {
    result.$defaultRef = $defaultRef
  }

  return result
}

// 转为符合绘图数据格式的互相引用对象
export function parseJsonToNodeTree(node: NodeJson): EventNode | undefined {
  if (!node)
    return undefined

  clearNodeMap()
  const result = parseJsonToNode(node)

  return result as EventNode
}
export function parseJsonToNode(node: NodeJson, parentNode?: BaseNode) {
  const { id, name, businessData, type, expressionRefs, childNode, nextNode, $defaultRef } = node

  // @ts-expect-error
  const result: BaseNode = createNode(type, undefined, name, businessData)
  result.id = id
  setNodeInMap(result)

  if (parentNode) {
    result.$parent = parentNode
  }

  if (nextNode) {
    const next = parseJsonToNode(nextNode, parentNode)
    result.$next = next
    next.$prev = result
  }
  if (childNode) {
    (result as SubprocessNode).$start = parseJsonToNode(childNode, result) as EventNode
  }
  if (expressionRefs) {
    (result as GatewayNode).$expressions = expressionRefs.map(d => parseJsonToNode(d, result)) as ExpressionNode[]
  }
  if ($defaultRef) {
    (result as GatewayNode).$default = (result as GatewayNode).$expressions.find(i => i.id === $defaultRef)
  }

  return result
}
